﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Net;
using System.Collections.ObjectModel;
using System.Text.RegularExpressions;
using System.Drawing.Imaging;
using MediaArtAggregator.Core;
using MediaArtAggregator.Core.SearchProvider;
using MediaArtAggregator.Core.Configuration;

namespace MediaArtAggregator {
	public partial class MainForm : Form {

		/// <summary>
		/// Gets or sets the results.
		/// </summary>
		/// <value>The results.</value>
		public Collection<Uri> Results { get; set; }
		/// <summary>
		/// Gets or sets the current page.
		/// </summary>
		/// <value>The current page.</value>
		public int CurrentPage { get; set; }
		/// <summary>
		/// Gets or sets the result pictures.
		/// </summary>
		/// <value>The result pictures.</value>
		public Collection<PictureBox> ResultPictures { get; private set; }
		/// <summary>
		/// Initializes a new instance of the <see cref="MainForm"/> class.
		/// </summary>
		public MainForm ( ) {
			Results = new Collection<Uri> ( );
			CurrentPage = 0;
			InitializeComponent ( );
			ResultPictures = new Collection<PictureBox> ( );
			CreatePictureBoxes ( );
			this.searchType.SelectedIndex = 0;
			this.searchType.Items.Clear ( );
			this.searchType.DataSource = Program.Settings.Types;
			this.searchType.ValueMember = "Value";
			this.searchType.DisplayMember = "Name";
			this.source.DataSource = Program.Settings.Sources;
			this.filename.Text = Program.Settings.OutputFileName;
			this.searchOnDoubleClick.Checked = Program.Settings.SearchOnDoubleClick;


		}

		protected override void OnLoad ( EventArgs e ) {
			base.OnLoad ( e );
			if ( !string.IsNullOrEmpty ( Program.Settings.Path ) && Directory.Exists ( Program.Settings.Path ) )
				this.folderPath.Text = Program.Settings.Path;
			else {
				this.filePathBrowse.PerformClick ( );
			}
		}

		/// <summary>
		/// Raises the <see cref="E:System.Windows.Forms.Form.Closing"/> event.
		/// </summary>
		/// <param name="e">A <see cref="T:System.ComponentModel.CancelEventArgs"/> that contains the event data.</param>
		protected override void OnClosing ( CancelEventArgs e ) {
			if ( !e.Cancel ) {
				Program.Settings.Save ( Program.SettingsFile );
			}
			base.OnClosing ( e );
		}

		/// <summary>
		/// Handles the Click event of the getMovies control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void getMovies_Click ( object sender, EventArgs e ) {

			DirectoryInfo rootDir = new DirectoryInfo ( this.folderPath.Text );
			foldersList.Nodes.Clear ( );
			if ( rootDir.Exists ) {
				BuildTree ( rootDir, foldersList.Nodes );
			}
		}

		/// <summary>
		/// Builds the tree.
		/// </summary>
		/// <param name="rootDir">The root dir.</param>
		/// <param name="treeNodeCollection">The tree node collection.</param>
		private void BuildTree ( DirectoryInfo rootDir, TreeNodeCollection treeNodeCollection ) {
			foreach ( DirectoryInfo dir in rootDir.GetDirectories ( ) ) {
				try {
					if ( ( dir.Attributes &= FileAttributes.System ) == 0 ) {
						TreeNode tn = new TreeNode ( dir.Name );
						tn.Tag = dir;
						treeNodeCollection.Add ( tn );
						BuildTree ( dir, tn.Nodes );
					}
				} catch ( Exception ex ) { }
			}
		}

		/// <summary>
		/// Handles the AfterSelect event of the foldersList control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Forms.TreeViewEventArgs"/> instance containing the event data.</param>
		private void foldersList_AfterSelect ( object sender, TreeViewEventArgs e ) {
			TreeNode selectedNode = e.Node;
			if ( e.Action != TreeViewAction.Collapse && e.Action != TreeViewAction.Expand && selectedNode != null && selectedNode.Tag != null ) {
				DirectoryInfo dir = selectedNode.Tag as DirectoryInfo;
				GetArtImage ( dir );
				this.title.Text = dir.Name;
				this.search.Enabled = true;
				this.title.Enabled = true;
				foreach ( PictureBox pb in this.ResultPictures ) {
					pb.Image = null;
					pb.Tag = null;
				}
			}
		}

		/// <summary>
		/// Gets the art image.
		/// </summary>
		/// <param name="dir">The dir.</param>
		private void GetArtImage ( DirectoryInfo dir ) {
			if ( Utilities.HasArtFile ( dir, Program.Settings.OutputFileName ) ) {
				FileStream fs = new FileStream ( Path.Combine ( dir.FullName, Program.Settings.OutputFileName + ".jpg" ), FileMode.Open, FileAccess.Read, FileShare.ReadWrite );
				using ( fs ) {
					Image temp = Image.FromStream ( fs );
					this.artImage.Image = Utilities.CreateImageWithSizeInfo ( temp, this.artImage.Size );
				}
				this.deleteSavedImage.Enabled = true;
			} else {
				this.artImage.Image = null;
				this.deleteSavedImage.Enabled = false;
			}
		}


		/// <summary>
		/// Handles the Click event of the search control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void search_Click ( object sender, EventArgs e ) {
			this.Cursor = Cursors.WaitCursor;
			Results.Clear ( );
			SearchSource source = this.source.SelectedItem as SearchSource;
			string artist = useParentAsArtist.Checked ? this.foldersList.SelectedNode != null ? this.foldersList.SelectedNode.Parent.Text + " " : "" : "";
			string searchString = string.Format ( "{0}{1}", artist, this.title.Text );
			source.Search ( searchString, Program.Settings, this.searchType.SelectedItem as SearchType );
			this.Results = source.Results;

			this.CurrentPage = 0;
			this.Text = string.Format ( "Media Art Aggregator - {0} Results found",
				this.Results.Count, Math.Ceiling ( (double)this.Results.Count / 3 ) );
			SetImageNavigation ( );
			ImageNavigate ( this.CurrentPage );
			this.Cursor = Cursors.Default;
		}

		/// <summary>
		/// Sets the image navigation.
		/// </summary>
		private void SetImageNavigation ( ) {
			this.prevResultSet.Enabled = this.CurrentPage > 0;
			this.nextResultSet.Enabled = this.Results.Count > 0 && ( this.CurrentPage + 1 ) < Math.Ceiling ( (double)this.Results.Count / 3 );
		}

		/// <summary>
		/// Images the navigate.
		/// </summary>
		/// <param name="page">The page.</param>
		private void ImageNavigate ( int page ) {
			this.Cursor = Cursors.WaitCursor;
			currentPage.Text = ( page + 1 ).ToString ( );
			int start = page * 3;
			for ( int index = 0; index < ResultPictures.Count; index++ ) {
				PictureBox pb = ResultPictures[index];
				try {
					if ( start + index < Results.Count ) {
						Console.WriteLine ( "URL: {0}", Results[start + index].ToString ( ) );
						HttpWebRequest req = HttpWebRequest.Create ( Results[start + index] ) as HttpWebRequest;
						HttpWebResponse resp = req.GetResponse ( ) as HttpWebResponse;
						Stream strm = resp.GetResponseStream ( );
						using ( strm ) {
							Image timg = Image.FromStream ( strm );
							pb.Image = Utilities.CreateImageWithSizeInfo ( timg, pb.Size );
							pb.Tag = timg;
						}
					} else {
						pb.Image = null;
						pb.Tag = null;
					}
				} catch ( Exception ex ) {
					pb.Image = GetNoImage ( );
					pb.Tag = null;
					Console.WriteLine ( ex.ToString ( ) );
				}
			}
			this.Cursor = Cursors.Default;
		}

		/// <summary>
		/// Creates the picture boxes.
		/// </summary>
		private void CreatePictureBoxes ( ) {
			Size s = new Size ( 132, 132 );
			Point pos = new Point ( 14, 7 );

			for ( int i = 0; i < 3; i++ ) {
				PictureBox pb = new PictureBox ( );
				pb.DoubleClick += new EventHandler ( this.result_DoubleClick );
				pb.BorderStyle = BorderStyle.FixedSingle;
				pb.SizeMode = PictureBoxSizeMode.StretchImage;
				pb.Cursor = Cursors.Hand;
				pb.Size = s;
				pb.Location = pos;
				pos.Offset ( 0, s.Height + 7 );
				ResultPictures.Add ( pb );
			}
			this.imagesPanel.Controls.AddRange ( ResultPictures.ToArray ( ) );
		}

		/// <summary>
		/// Gets the no image.
		/// </summary>
		/// <returns></returns>
		private Image GetNoImage ( ) {
			return Properties.Resources.noimage;
		}

		/// <summary>
		/// Handles the LinkClicked event of the prevResultSet control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Forms.LinkLabelLinkClickedEventArgs"/> instance containing the event data.</param>
		private void prevResultSet_LinkClicked ( object sender, LinkLabelLinkClickedEventArgs e ) {
			if ( this.CurrentPage > 0 ) {
				this.CurrentPage--;
				this.ImageNavigate ( this.CurrentPage );
			}
			SetImageNavigation ( );

		}

		/// <summary>
		/// Handles the LinkClicked event of the nextResultSet control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Forms.LinkLabelLinkClickedEventArgs"/> instance containing the event data.</param>
		private void nextResultSet_LinkClicked ( object sender, LinkLabelLinkClickedEventArgs e ) {
			if ( this.CurrentPage <= (int)Math.Ceiling ( (double)this.Results.Count / 3 ) ) {
				this.CurrentPage++;
				this.ImageNavigate ( this.CurrentPage );
			}
			SetImageNavigation ( );

		}

		/// <summary>
		/// Handles the DoubleClick event of the result control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void result_DoubleClick ( object sender, EventArgs e ) {
			if ( sender is PictureBox && foldersList.SelectedNode != null && foldersList.SelectedNode.Tag != null ) {
				PictureBox pb = sender as PictureBox;
				if ( pb.Image != null && pb.Tag != null && pb.Tag is Image ) {
					Image t = pb.Tag as Image;
					deleteSavedImage.PerformClick ( );
					DirectoryInfo dir = (DirectoryInfo)foldersList.SelectedNode.Tag;
					t.Save ( Path.Combine ( dir.FullName, Program.Settings.OutputFileName + ".jpg" ), ImageFormat.Jpeg );
					GetArtImage ( dir );
					if ( Utilities.HasArtFile ( dir, Program.Settings.OutputFileName ) ) {
						foldersList.SelectedNode.BackColor = foldersList.BackColor;
					}
				}
			}
		}

		/// <summary>
		/// Handles the Click event of the deleteSavedImage control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void deleteSavedImage_Click ( object sender, EventArgs e ) {
			if ( foldersList.SelectedNode != null && foldersList.SelectedNode.Tag != null ) {
				DirectoryInfo dir = (DirectoryInfo)foldersList.SelectedNode.Tag;
				FileInfo image = new FileInfo ( Path.Combine ( dir.FullName, Program.Settings.OutputFileName + ".jpg" ) );
				if ( image.Exists )
					image.Delete ( );
				GetArtImage ( dir );
			}
		}

		/// <summary>
		/// Handles the Click event of the showNoCover control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void showNoCover_Click ( object sender, EventArgs e ) {
			FindNoArt ( this.foldersList.Nodes );
		}

		/// <summary>
		/// Finds the no art.
		/// </summary>
		/// <param name="treeNodeCollection">The tree node collection.</param>
		private void FindNoArt ( TreeNodeCollection treeNodeCollection ) {
			foreach ( TreeNode tn in treeNodeCollection ) {
				if ( ignoreRootForNoArt.Checked && tn.Parent == null ) {
					FindNoArt ( tn.Nodes );
					continue;
				}
				DirectoryInfo dir = (DirectoryInfo)tn.Tag;
				if ( !Utilities.HasArtFile ( dir, Program.Settings.OutputFileName ) ) {
					tn.BackColor = Utilities.GetColorFromString ( Program.Settings.HighlightColor );
					tn.EnsureVisible ( );
				}
				FindNoArt ( tn.Nodes );
			}
		}

		/// <summary>
		/// Handles the NodeMouseDoubleClick event of the foldersList control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Forms.TreeNodeMouseClickEventArgs"/> instance containing the event data.</param>
		private void foldersList_NodeMouseDoubleClick ( object sender, TreeNodeMouseClickEventArgs e ) {
			if ( this.searchOnDoubleClick.Checked ) {
				this.search.PerformClick ( );
			}
		}

		/// <summary>
		/// Handles the Click event of the expandAll control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void expandAll_Click ( object sender, EventArgs e ) {
			this.foldersList.ExpandAll ( );
		}

		/// <summary>
		/// Handles the Click event of the collapseAll control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void collapseAll_Click ( object sender, EventArgs e ) {
			this.foldersList.CollapseAll ( );
		}

		/// <summary>
		/// Handles the Click event of the filePathBrowse control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void filePathBrowse_Click ( object sender, EventArgs e ) {
			FolderBrowserDialog fbd = new FolderBrowserDialog ( );
			fbd.ShowNewFolderButton = false;
			fbd.RootFolder = Environment.SpecialFolder.Desktop;
			fbd.Description = "Select Media Directory";
			if ( !string.IsNullOrEmpty ( Program.Settings.Path ) )
				fbd.SelectedPath = Program.Settings.Path;
			if ( fbd.ShowDialog ( this ) == DialogResult.OK ) {
				this.folderPath.Text = Program.Settings.Path = fbd.SelectedPath;
			}
		}

		private void setFileName_Click ( object sender, EventArgs e ) {
			Program.Settings.OutputFileName = string.IsNullOrEmpty ( this.filename.Text.Trim ( ) ) ? "folder" : this.filename.Text.Trim ( );
		}

	}
}
